
<!DOCTYPE html>

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />

    <title>Leo’s WebSocket Server &#8212; Leo 6.7.2 documentation</title>
    <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
    <link rel="stylesheet" type="text/css" href="_static/classic.css" />
    <link rel="stylesheet" type="text/css" href="_static/custom.css" />
    
    <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
    <script src="_static/jquery.js"></script>
    <script src="_static/underscore.js"></script>
    <script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
    <script src="_static/doctools.js"></script>
    <script src="_static/sphinx_highlight.js"></script>
    
    <script src="_static/sidebar.js"></script>
    
    <link rel="index" title="Index" href="genindex.html" />
    <link rel="search" title="Search" href="search.html" />
    <link rel="next" title="Advanced Topics" href="intermediatetopics.html" />
    <link rel="prev" title="ILeo: Leo’s IPython Bridge" href="IPythonBridge.html" /> 
  </head><body>
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="genindex.html" title="General Index"
             accesskey="I">index</a></li>
        <li class="right" >
          <a href="intermediatetopics.html" title="Advanced Topics"
             accesskey="N">next</a> |</li>
        <li class="right" >
          <a href="IPythonBridge.html" title="ILeo: Leo’s IPython Bridge"
             accesskey="P">previous</a> |</li>
        <li class="nav-item nav-item-0"><a href="leo_toc.html">Leo 6.7.2 documentation</a> &#187;</li>
          <li class="nav-item nav-item-1"><a href="leoandotherprograms.html" accesskey="U">Leo and Other Programs</a> &#187;</li>
        <li class="nav-item nav-item-this"><a href="">Leo’s WebSocket Server</a></li> 
      </ul>
    </div>  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body" role="main">
            
  <section id="leo-s-websocket-server">
<h1>Leo’s WebSocket Server<a class="headerlink" href="#leo-s-websocket-server" title="Permalink to this heading">¶</a></h1>
<p>leo/core/leoserver.py is websocket server providing Leo’s resources to
clients. The server offers single or multiple concurrent websockets.</p>
<p><em>WebSocket is a computer communications protocol, providing full-duplex
communication channels over a single TCP connection.</em></p>
<p>Clients can be written in any language:
- leo.core.leoclient is an example client written in python.
- leoInteg (<a class="reference external" href="https://github.com/boltex/leointeg">https://github.com/boltex/leointeg</a>) is written in typescript.</p>
<p>At startup, the server creates a single instance of Leo’s bridge. (core.leoBridge)
Clients can open (or create) Leo outlines in the bridge. Thereafter,
clients can query or change the contents of the outlines.</p>
<p>Clients encode requests as JSON strings and receive results from the server
as JSON strings.</p>
<p>Run the leoserver.py script with the “–help” command line parameter to learn
more about the server’s capabilities.</p>
<div class="contents local topic" id="contents">
<p class="topic-title">Contents</p>
<ul class="simple">
<li><p><a class="reference internal" href="#the-communication-protocol" id="id1">The communication protocol</a></p>
<ul>
<li><p><a class="reference internal" href="#requests" id="id2">Requests</a></p></li>
<li><p><a class="reference internal" href="#responses" id="id3">Responses</a></p></li>
<li><p><a class="reference internal" href="#async-messages" id="id4">Async messages</a></p></li>
</ul>
</li>
<li><p><a class="reference internal" href="#the-main-server-loop" id="id5">The main server loop</a></p></li>
<li><p><a class="reference internal" href="#compatibility-and-extensibility" id="id6">Compatibility and extensibility</a></p></li>
<li><p><a class="reference internal" href="#multiple-concurrent-connections" id="id7">Multiple concurrent connections</a></p></li>
<li><p><a class="reference internal" href="#command-line-arguments" id="id8">Command line arguments</a></p></li>
<li><p><a class="reference internal" href="#acknowledgments" id="id9">Acknowledgments</a></p></li>
</ul>
</div>
<section id="the-communication-protocol">
<h2><a class="toc-backref" href="#id1">The communication protocol</a><a class="headerlink" href="#the-communication-protocol" title="Permalink to this heading">¶</a></h2>
<p>The following sections describe the communication protocol, that is, the
format of requests sent from the client and responses sent from the server.</p>
<section id="requests">
<h3><a class="toc-backref" href="#id2">Requests</a><a class="headerlink" href="#requests" title="Permalink to this heading">¶</a></h3>
<p>JSON requests (from the client to the server) must have three keys:</p>
<p>“id”: A string containing a positive integer.</p>
<p>“action”: A string denoting the kind of request. There are three forms:</p>
<ol class="arabic simple">
<li><p>Actions prefixed with ‘!’ must be the name of public method of the
LeoServer class in leoserver.py.</p></li>
<li><p>Actions prefixed with ‘-’ must be the name of a Leo command.</p></li>
<li><p>Otherwise, the action must be name of a method in one of Leo’s
subcommander classes.</p></li>
</ol>
<p>“param”: A dict containing additional information. The param key often
contains “ap”, “text” and “keep” keys.</p>
<p>The server’s <strong>_ap_to_p</strong> and <strong>_p_to_ap</strong> methods convert Leo positions to
<strong>archived positions</strong> (strings) that can be converted to JSON.</p>
<p>The “action” and “param” members mimic the “function name” and “parameters” or
a procedure call. And is in fact implemented as a remote procedure call.</p>
<p>The LeoServer._do_message method checks and handles incoming requests in a
one by one, blocking synchronous manner.</p>
</section>
<section id="responses">
<h3><a class="toc-backref" href="#id3">Responses</a><a class="headerlink" href="#responses" title="Permalink to this heading">¶</a></h3>
<p>JSON responses (from the server to the client) always have the following keys
unless the request was a ‘getter’ command:</p>
<ul class="simple">
<li><p>“id”: The incoming request id this JSON message is responding to.</p></li>
<li><p>“commander”: A dict describing c, the open commander.</p></li>
<li><p>“node”:  None, or an archived position describing c.p.</p></li>
</ul>
<p>Optional keys:</p>
<ul class="simple">
<li><p>“package”: A dict containing extra data.</p></li>
<li><p>“p”: “An archived position”.</p></li>
</ul>
<p>If the request was a ‘getter’ command, the JSON response will only contain the
specific structure that was requested.</p>
</section>
<section id="async-messages">
<h3><a class="toc-backref" href="#id4">Async messages</a><a class="headerlink" href="#async-messages" title="Permalink to this heading">¶</a></h3>
<p>The server also sends asynchronous messages, i.e. messages that are not responses
to a specific request, that are meant to communicate a changed state or request
a user input through a modal dialog, or anything else that was not initiated by
a connected clients’ direct request.</p>
<p>Examples of ‘async’ messages:</p>
<ul class="simple">
<li><p>An entry added to the log pane.</p></li>
<li><p>Signal the detection of an external file change.</p></li>
<li><p>Signal the automatic refresh of an outline.</p></li>
<li><p>A signal to ask the user about reloading a Leo file that has changed after changing a git branch.</p></li>
</ul>
</section>
</section>
<section id="the-main-server-loop">
<h2><a class="toc-backref" href="#id5">The main server loop</a><a class="headerlink" href="#the-main-server-loop" title="Permalink to this heading">¶</a></h2>
<p>The <strong>ws_handler</strong> function contains the main server loop.</p>
<p>ws_handler dispatches incoming requests to the <strong>_do_request</strong> method,
which then calls the appropriate handler, either in the LeoServer class, or
(via Leo’s bridge) to Leo itself.</p>
<p>Request handlers raise the following exceptions:</p>
<ul class="simple">
<li><p>ServerError indicates an invalid user request.
The server returns a response describing the error.</p></li>
<li><p>InternalServerError and error within the server itself.
The server prints an error message and stops.</p></li>
<li><p>TerminateServer causes the server to terminate normally.</p></li>
</ul>
</section>
<section id="compatibility-and-extensibility">
<h2><a class="toc-backref" href="#id6">Compatibility and extensibility</a><a class="headerlink" href="#compatibility-and-extensibility" title="Permalink to this heading">¶</a></h2>
<p>Requests from the client to the server may reference:</p>
<ul class="simple">
<li><p>Public methods of the LeoServer class.</p></li>
<li><p>The names of Leo commands.</p></li>
<li><p>Methods of Leo’s subcommander classes.</p></li>
</ul>
<p>The public methods of the LeoServer class can only be changed in an upward
compatible manner. If necessary, new public methods can be added at any
time.</p>
<p>Leo is a programming environment in which user scripts can access all of
Leo’s source code. For this reason, the names of methods in Leo’s core
change rarely. Similarly, clients can usually assume that the names of Leo
commands won’t change.</p>
</section>
<section id="multiple-concurrent-connections">
<h2><a class="toc-backref" href="#id7">Multiple concurrent connections</a><a class="headerlink" href="#multiple-concurrent-connections" title="Permalink to this heading">¶</a></h2>
<p>Since a WebSocket server can receive events from clients, process them to update the
application state, and synchronize the resulting state across clients, leoserver.py
has the ability to listen and interact with more than one concurrent client, and have
the state of the underlying Leo core application be represented in real time to all
connected clients.</p>
<p>If a server is started with the command line argument parameter ‘limit’ set to more than one (1),
then it will allow for more than one client to be connected at the same time, sharing in real
time the state, and control, of the underlying Leo instance.</p>
<p>This can be used to have multiple client programs share the same views and functionality
of a single Leo instance. Or be used to live-share the editing process with collaborators
or spectators in real time.</p>
<p><em>By default, this limit is set to one (1) to prevent multiple connections and force each client
to have their own individual Leo server instances running on different ports.</em></p>
</section>
<section id="command-line-arguments">
<h2><a class="toc-backref" href="#id8">Command line arguments</a><a class="headerlink" href="#command-line-arguments" title="Permalink to this heading">¶</a></h2>
<p>leoserver.py has optional command line arguments that you can provide
to get specific behaviors from the server.</p>
<p><strong>–file &lt;filename&gt; or -f &lt;filename&gt;</strong></p>
<blockquote>
<div><p>Open the given file after starting the server.</p>
</div></blockquote>
<p><strong>–persist</strong></p>
<blockquote>
<div><p>Prevent the server from closing when last client disconnects</p>
</div></blockquote>
<p><strong>–limit &lt;number&gt; or -l &lt;number&gt;</strong></p>
<blockquote>
<div><p>Allow more than one connection to be open simultaneously.
By default, only one connection may be open at a time.</p>
</div></blockquote>
<p><strong>–address &lt;address&gt; or -a &lt;address&gt;</strong></p>
<blockquote>
<div><p>Set the listening address.</p>
</div></blockquote>
<p><strong>–port &lt;number&gt; or -p &lt;number&gt;</strong></p>
<blockquote>
<div><p>Set the listening port.</p>
</div></blockquote>
<p><strong>–help or -h</strong></p>
<blockquote>
<div><p>List all available command-line arguments.</p>
</div></blockquote>
</section>
<section id="acknowledgments">
<h2><a class="toc-backref" href="#id9">Acknowledgments</a><a class="headerlink" href="#acknowledgments" title="Permalink to this heading">¶</a></h2>
<p>Félix Malboeuf wrote the original version of leoserver.py, including the
first draft of the all-important ws_handler function.</p>
<p>Edward K. Ream made the code more pythonic and provided Leo-specific
advice.</p>
</section>
</section>


            <div class="clearer"></div>
          </div>
        </div>
      </div>
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
            <p class="logo"><a href="leo_toc.html">
              <img class="logo" src="_static/LeoLogo.svg" alt="Logo"/>
            </a></p>
  <div>
    <h4>Previous topic</h4>
    <p class="topless"><a href="IPythonBridge.html"
                          title="previous chapter">ILeo: Leo’s IPython Bridge</a></p>
  </div>
  <div>
    <h4>Next topic</h4>
    <p class="topless"><a href="intermediatetopics.html"
                          title="next chapter">Advanced Topics</a></p>
  </div>
<div id="searchbox" style="display: none" role="search">
  <h3 id="searchlabel">Quick search</h3>
    <div class="searchformwrapper">
    <form class="search" action="search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>
    </div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
        </div>
<div id="sidebarbutton" title="Collapse sidebar">
<span>«</span>
</div>

      </div>
      <div class="clearer"></div>
    </div>
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="genindex.html" title="General Index"
             >index</a></li>
        <li class="right" >
          <a href="intermediatetopics.html" title="Advanced Topics"
             >next</a> |</li>
        <li class="right" >
          <a href="IPythonBridge.html" title="ILeo: Leo’s IPython Bridge"
             >previous</a> |</li>
        <li class="nav-item nav-item-0"><a href="leo_toc.html">Leo 6.7.2 documentation</a> &#187;</li>
          <li class="nav-item nav-item-1"><a href="leoandotherprograms.html" >Leo and Other Programs</a> &#187;</li>
        <li class="nav-item nav-item-this"><a href="">Leo’s WebSocket Server</a></li> 
      </ul>
    </div>
    <div class="footer" role="contentinfo">
        &#169; Copyright 1997-2023, Edward K. Ream.
      Last updated on February 28, 2023.
      Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 5.3.0.
    </div>
  </body>
</html>